package com.vca.service.service.Impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vca.common.constants.Constants;
import com.vca.common.constants.CouponConstants;
import com.vca.common.constants.OrderRedisConstans;
import com.vca.common.exception.VcaException;
import com.vca.common.model.course.Course;
import com.vca.common.model.course.CoursePackageRelation;
import com.vca.common.model.course.CourseScheduling;
import com.vca.common.model.exhibition.ExhibitionScheduling;
import com.vca.common.model.order.StoreOrder;
import com.vca.common.model.order.StoreOrderInfo;
import com.vca.common.model.sms.SmsTemplate;
import com.vca.common.model.system.SystemNotification;
import com.vca.common.model.talk.TalkScheduling;
import com.vca.common.model.user.User;
import com.vca.common.model.user.UserCard;
import com.vca.common.model.user.UserToken;
import com.vca.common.model.vca_product.VcaProduct;
import com.vca.common.model.vca_product.VcaProductAttrValue;
import com.vca.common.response.VcaStockResponse;
import com.vca.common.vo.PreOrderCommonVo;
import com.vca.common.vo.VcaProductStockVo;
import com.vca.service.service.*;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.*;

/**
 * StoreOrderTaskService实现类
 */
@Service
public class StoreOrderTaskServiceImpl implements StoreOrderTaskService {
    //日志
    private static final Logger logger = LoggerFactory.getLogger(StoreOrderTaskServiceImpl.class);

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private VcaOrderService vcaOrderService;

    @Autowired
    private StoreOrderStatusService storeOrderStatusService;

    @Autowired
    private UserCardService userCardService;

    @Autowired
    private CourseSchedulingService courseSchedulingService;

    @Autowired
    private CoursePackageService coursePackageService;

    @Autowired
    private CoursePackageRelationService coursePackageRelationService;

    @Autowired
    private TalkSchedulingService talkSchedulingService;

    @Autowired
    private ExhibitionSchedulingService exhibitionSchedulingService;

    @Autowired
    private VcaProductService vcaProductService;

    @Autowired
    private VcaProductAttrValueService vcaProductAttrValueService;

    @Autowired
    private StoreOrderInfoService storeOrderInfoService;

    @Autowired
    private TemplateMessageService templateMessageService;

    @Autowired
    private UserTokenService userTokenService;

    @Autowired
    private SystemNotificationService systemNotificationService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private SmsTemplateService smsTemplateService;

    @Autowired
    private UserService userService;

    @Autowired
    private StoreOrderService storeOrderService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private VcaLineUpService vcaLineUpService;


    /**
     * 前台订单取消
     *
     * @param storeOrder
     * @return
     */
    @Override
    public Boolean cancelByUser(StoreOrder storeOrder) {
        try {
            //todo 用户取消订单，发送排队等级消息通知
            handleSendMessage(storeOrder);
            /*
             * 1、修改订单状态 （用户操作的时候已处理）
             * 2、写订单日志（用户操作的时候已处理）
             * 3、回滚商品库存（加）/销量（减）；虚拟物品回滚限量（加）/预约人数（减）、礼品卡回滚,将订单号放到redis指定的key中【Task】
             * 4、消息通知（生成对应的模板消息存入对应的key中）【Task】
             * */
            //回滚礼品卡
            Boolean execute = transactionTemplate.execute(e -> {
                if (storeOrder.getCouponId() > 0) {
                    UserCard userCard = userCardService.getById(storeOrder.getCouponId());
                    userCard.setStutus(CouponConstants.STORE_COUPON_USER_STATUS_USABLE);
                    userCardService.updateById(userCard);
                }
                //回滚库存
                VcaProductStockVo vcaProductStockVo = vcaOrderService.rollBackStock(storeOrder);
                List<CourseScheduling> courseSchedulingList = vcaProductStockVo.getCourseSchedulingList();
                List<TalkScheduling> talkSchedulingList = vcaProductStockVo.getTalkSchedulingList();
                List<ExhibitionScheduling> exhibitionSchedulingList = vcaProductStockVo.getExhibitionSchedulingList();
                List<VcaProduct> vcaProducts = vcaProductStockVo.getVcaProducts();
                List<VcaProductAttrValue> vcaProductAttrValues = vcaProductStockVo.getVcaProductAttrValues();
                if (courseSchedulingList.size() > 0) {
                    courseSchedulingService.updateBatchById(courseSchedulingList);
                }
                if (talkSchedulingList.size() > 0) {
                    talkSchedulingService.updateBatchById(talkSchedulingList);
                }
                if (exhibitionSchedulingList.size() > 0) {
                    exhibitionSchedulingService.updateBatchById(exhibitionSchedulingList);
                }
                if (vcaProducts.size() > 0) {
                    vcaProductService.updateBatchById(vcaProducts);
                }
                if (vcaProductAttrValues.size() > 0) {
                    vcaProductAttrValueService.updateBatchById(vcaProductAttrValues);
                }
                // TODO: 2022/12/30 推送消息提醒
                frontOrderCancel(storeOrder);
                return Boolean.TRUE;
            });
            if (!execute) {
                throw new VcaException("取消订单失败");
            } else {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }

    private void handleSendMessage(StoreOrder storeOrder) {
        if (storeOrder.getType() == 4) {
            return;
        }
        List<StoreOrderInfo> listByOrderNo = storeOrderInfoService.getListByOrderNo(storeOrder.getOrderId());
        if (listByOrderNo.size() <= 0) {
            return;
        }
        Long mainId = listByOrderNo.get(0).getMainId();
        Integer type = listByOrderNo.get(0).getType();
        switch (type) {
            case 0:
                CourseScheduling courseSchedul = courseSchedulingService.getById(listByOrderNo.get(0).getSchedulingId());
                if (!courseSchedulingService.checkSchedulingQuta(mainId) || !courseSchedulingService.checkSchedulingDate(courseSchedul)) {
                    return;
                }
                break;
            case 1:
                List<CoursePackageRelation> coursePackageRelationList = coursePackageRelationService.list(new LambdaQueryWrapper<CoursePackageRelation>().eq(CoursePackageRelation::getCoursePackageId, mainId));
                for (CoursePackageRelation coursePackageRelation : coursePackageRelationList) {
                    PreOrderCommonVo.CourseInfoDetail courseInfoDetail = JSONObject.parseObject(listByOrderNo.get(0).getInfo(), PreOrderCommonVo.CourseInfoDetail.class);
                    List<PreOrderCommonVo.CourseInfoDetail.Scheduling> schedulings = courseInfoDetail.getSchedulings();
                    for (PreOrderCommonVo.CourseInfoDetail.Scheduling scheduling : schedulings) {
                        CourseScheduling courseScheduling = courseSchedulingService.getById(scheduling.getScheduleId());
                        if (!courseSchedulingService.checkSchedulingQuta(coursePackageRelation.getCourseId()) || !courseSchedulingService.checkSchedulingDate(courseScheduling)) {
                            return;
                        }
                    }
                }
                break;
            case 2:
                TalkScheduling talkScheduling = talkSchedulingService.getById(listByOrderNo.get(0).getSchedulingId());
                if (!talkSchedulingService.checkSchedulingQuta(mainId) || !talkSchedulingService.checkSchedulingDate(talkScheduling, mainId)) {
                    return;
                }
                break;
            case 3:
                ExhibitionScheduling exhibitionScheduling = exhibitionSchedulingService.getById(listByOrderNo.get(0).getSchedulingId());
                if (!exhibitionSchedulingService.checkSchedulingQuta(mainId) || !exhibitionSchedulingService.checkSchedulingDate(exhibitionScheduling)) {
                    return;
                }
                break;
            default:
                break;
        }
        vcaLineUpService.noticeByMainId(mainId, type);
    }

    /**
     * 活动取消
     *
     * @param storeOrder
     * @return
     */
    @Override
    public Boolean activityCancelByUser(StoreOrder storeOrder, Long schedulingId) {
        try {
            /*
             * 1、修改订单状态 （用户操作的时候已处理）
             * 2、写订单日志（用户操作的时候已处理）
             * 3、回滚商品库存（加）/销量（减）；虚拟物品回滚限量（加）/预约人数（减）、礼品卡回滚,将订单号放到redis指定的key中【Task】
             * 4、消息通知（生成对应的模板消息存入对应的key中）【Task】
             * */

            //回滚礼品卡
            Boolean execute = transactionTemplate.execute(e -> {
                if (storeOrder.getCouponId() > 0) {
                    UserCard userCard = userCardService.getById(storeOrder.getCouponId());
                    userCard.setStutus(CouponConstants.STORE_COUPON_USER_STATUS_USABLE);
                    userCardService.updateById(userCard);
                }
                //回滚库存
                VcaProductStockVo vcaProductStockVo = storeOrderService.rollBackStock(storeOrder);
                List<CourseScheduling> courseSchedulingList = vcaProductStockVo.getCourseSchedulingList();
                List<TalkScheduling> talkSchedulingList = vcaProductStockVo.getTalkSchedulingList();
                List<ExhibitionScheduling> exhibitionSchedulingList = vcaProductStockVo.getExhibitionSchedulingList();
                List<VcaProduct> vcaProducts = vcaProductStockVo.getVcaProducts();
                List<VcaProductAttrValue> vcaProductAttrValues = vcaProductStockVo.getVcaProductAttrValues();
                if (courseSchedulingList.size() > 0) {
                    courseSchedulingService.updateBatchById(courseSchedulingList);
                }
                if (talkSchedulingList.size() > 0) {
                    talkSchedulingService.updateBatchById(talkSchedulingList);
                }
                if (exhibitionSchedulingList.size() > 0) {
                    exhibitionSchedulingService.updateBatchById(exhibitionSchedulingList);
                }
                if (vcaProducts.size() > 0) {
                    vcaProductService.updateBatchById(vcaProducts);
                }
                if (vcaProductAttrValues.size() > 0) {
                    vcaProductAttrValueService.updateBatchById(vcaProductAttrValues);
                }
                storeOrderStatusService.createLog(storeOrder.getId(), "activityCancel", 0, "活动取消");
                // TODO: 2022/12/30 推送消息提醒
                activityCancelPushMessage(storeOrder, schedulingId);
                return Boolean.TRUE;
            });
            if (!execute) {
                throw new VcaException("活动取消失败");
            } else {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 后台取消课程讲座展览订单
     *
     * @param storeOrder
     * @return
     */
    @Override
    public Boolean adminOrderCancelByUser(StoreOrder storeOrder) {
        try {
            handleSendMessage(storeOrder);
            /*
             * 3、虚拟物品回滚限量（加）/预约人数（减）、礼品卡回滚,将订单号放到redis指定的key中【Task】
             * 4、消息通知（生成对应的模板消息存入对应的key中）【Task】
             * */
            //回滚礼品卡
            Boolean execute = transactionTemplate.execute(e -> {//todo 套课回滚库存处理
                if (storeOrder.getCouponId() > 0) {
                    UserCard userCard = userCardService.getById(storeOrder.getCouponId());
                    userCard.setStutus(CouponConstants.STORE_COUPON_USER_STATUS_USABLE);
                    userCardService.updateById(userCard);
                }
                //回滚库存
                //回滚库存
                VcaProductStockVo vcaProductStockVo = storeOrderService.rollBackStock(storeOrder);
                List<CourseScheduling> courseSchedulingList = vcaProductStockVo.getCourseSchedulingList();
                List<TalkScheduling> talkSchedulingList = vcaProductStockVo.getTalkSchedulingList();
                List<ExhibitionScheduling> exhibitionSchedulingList = vcaProductStockVo.getExhibitionSchedulingList();
                List<VcaProduct> vcaProducts = vcaProductStockVo.getVcaProducts();
                List<VcaProductAttrValue> vcaProductAttrValues = vcaProductStockVo.getVcaProductAttrValues();
                if (courseSchedulingList.size() > 0) {
                    courseSchedulingService.updateBatchById(courseSchedulingList);
                }
                if (talkSchedulingList.size() > 0) {
                    talkSchedulingService.updateBatchById(talkSchedulingList);
                }
                if (exhibitionSchedulingList.size() > 0) {
                    exhibitionSchedulingService.updateBatchById(exhibitionSchedulingList);
                }
                if (vcaProducts.size() > 0) {
                    vcaProductService.updateBatchById(vcaProducts);
                }
                if (vcaProductAttrValues.size() > 0) {
                    vcaProductAttrValueService.updateBatchById(vcaProductAttrValues);
                }
                // TODO: 2022/12/30 推送消息提醒
                adminOrderCancelPushMessage(storeOrder);
                return Boolean.TRUE;
            });
            if (!execute) {
                throw new VcaException("后台取消订单失败");
            } else {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 商品回滚库存
     *
     * @param storeOrder
     * @return
     */
    @Override
    public Boolean orderRefundProductByUser(StoreOrder storeOrder) {
        try {
            /*
             * 3、虚拟物品回滚限量（加）/预约人数（减）、礼品卡回滚,将订单号放到redis指定的key中【Task】
             * 4、消息通知（生成对应的模板消息存入对应的key中）【Task】
             * */
//            StoreOrder storeOrder = storeOrderService.getByOrderId(storeOrderInfo.getOrderNo());
            //回滚礼品卡

            Boolean execute = transactionTemplate.execute(e -> {
                if (storeOrder.getCouponId() > 0) {
                    UserCard userCard = userCardService.getById(storeOrder.getCouponId());
                    userCard.setStutus(CouponConstants.STORE_COUPON_USER_STATUS_USABLE);
                    userCardService.updateById(userCard);
                }
                //回滚库存
                VcaProductStockVo vcaProductStockVo = rollBackStock(storeOrder);
                List<VcaProduct> vcaProducts = vcaProductStockVo.getVcaProducts();
                List<VcaProductAttrValue> vcaProductAttrValues = vcaProductStockVo.getVcaProductAttrValues();
                if (vcaProducts.size() > 0) {
                    vcaProductService.updateBatchById(vcaProducts);
                }
                if (vcaProductAttrValues.size() > 0) {
                    vcaProductAttrValueService.updateBatchById(vcaProductAttrValues);
                }
                return Boolean.TRUE;
            });
            if (!execute) {
                throw new VcaException("商品订单退款回滚库存失败");
            } else {
                List<StoreOrderInfo> orderInfoList = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()).eq(StoreOrderInfo::getRefundStatus, 2));
                orderConsentRefund(storeOrder, orderInfoList);//消息通知
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }


    @Override
    public Boolean complete(StoreOrder storeOrder) {
        return null;
    }

    @Override
    public Boolean refundOrder(StoreOrder storeOrder) {
        return null;
    }

    /**
     * @Description:自动取消未支付订单
     * @author:chenbing
     * @date 2022/12/7 13:47
     */
    @Override
    public Boolean autoCancel(StoreOrder storeOrder) {
        // TODO: 2022/12/7 判断当前订单是否支付
        if (storeOrder.getPaid()) {
            return Boolean.TRUE;
        }
        if (storeOrder.getIsDel() || storeOrder.getIsSystemDel()) {
            return Boolean.TRUE;
        }
        // TODO: 2022/12/7 根据订单类型获取过期时间
        String cancelStr = null;
        switch (storeOrder.getType()) {
            //0-课程订单
            case 0:
                cancelStr = systemConfigService.getValueByKey(Constants.COURSE_CANCEL_TIME);
                break;
            //1=套课订单
            case 1:
                cancelStr = systemConfigService.getValueByKey(Constants.COURSE_CANCEL_TIME);
                break;
            //2=讲座订单
            case 2:
                cancelStr = systemConfigService.getValueByKey(Constants.TALK_CANCEL_TIME);
                break;
            //3=展览订单
            case 3:
                cancelStr = systemConfigService.getValueByKey(Constants.EXHIBITION_CANCEL_TIME);
                break;
            // 4=商品订单
            case 4:
                cancelStr = systemConfigService.getValueByKey(Constants.ORDER_CANCEL_TIME);
                break;
            default:
                break;
        }
        DateTime cancelTime = cn.hutool.core.date.DateUtil.offset(storeOrder.getCreateTime(), DateField.MINUTE, Integer.parseInt(cancelStr));
        long between = cn.hutool.core.date.DateUtil.between(cancelTime, cn.hutool.core.date.DateUtil.date(), DateUnit.SECOND, false);
        if (between < 0) {// 未到过期时间继续循环
            return Boolean.FALSE;
        }
        storeOrder.setIsDel(true);
        storeOrder.setIsSystemDel(true);
        //todo 用户取消订单，发送排队等级消息通知
        handleSendMessage(storeOrder);
        Boolean execute = transactionTemplate.execute(e -> {
            vcaOrderService.updateById(storeOrder);
            // TODO: 2022/12/7 写订单日志
            storeOrderStatusService.createLog(storeOrder.getId(), "cancel", 0, "到期未支付系统自动取消");
            // TODO: 2022/12/7 退优惠券
            if (storeOrder.getCouponId() > 0) {
                UserCard userCard = userCardService.getById(storeOrder.getCouponId());
                userCard.setStutus(CouponConstants.STORE_COUPON_USER_STATUS_USABLE);
                userCardService.updateById(userCard);
            }
            // TODO: 2022/12/30 回滚库存
            VcaProductStockVo vcaProductStockVo = vcaOrderService.rollBackStock(storeOrder);
            List<CourseScheduling> courseSchedulingList = vcaProductStockVo.getCourseSchedulingList();
            List<TalkScheduling> talkSchedulingList = vcaProductStockVo.getTalkSchedulingList();
            List<ExhibitionScheduling> exhibitionSchedulingList = vcaProductStockVo.getExhibitionSchedulingList();
            List<VcaProduct> vcaProducts = vcaProductStockVo.getVcaProducts();
            List<VcaProductAttrValue> vcaProductAttrValues = vcaProductStockVo.getVcaProductAttrValues();
            if (courseSchedulingList.size() > 0) {
                courseSchedulingService.updateBatchById(courseSchedulingList);
            }
            if (talkSchedulingList.size() > 0) {
                talkSchedulingService.updateBatchById(talkSchedulingList);
            }
            if (exhibitionSchedulingList.size() > 0) {
                exhibitionSchedulingService.updateBatchById(exhibitionSchedulingList);
            }
            if (vcaProducts.size() > 0) {
                vcaProductService.updateBatchById(vcaProducts);
            }
            if (vcaProductAttrValues.size() > 0) {
                vcaProductAttrValueService.updateBatchById(vcaProductAttrValues);
            }
            // TODO: 2022/12/30 推送消息提醒
            try {
                pushMessageTip(storeOrder, "订单超时");
            } catch (Exception ex) {
                return Boolean.FALSE;
            }
            return Boolean.TRUE;
        });
        if (!execute) {
            throw new VcaException("自动取消未支付订单失败");
        }
        return Boolean.TRUE;
    }

    /**
     * 退货超时取消
     *
     * @param storeOrder
     * @return
     */
    @Override
    public Boolean returnTimeout(StoreOrder storeOrder) {

        List<StoreOrderInfo> storeOrderInfoList = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()).eq(StoreOrderInfo::getRefundStatus, 4));
        // 判断当前订单是否已寄出
        if (storeOrder.getRefundStatus().equals(5) || storeOrder.getRefundStatus().equals(6) || storeOrder.getRefundStatus().equals(2) || storeOrder.getRefundStatus().equals(3)) {
            return Boolean.TRUE;
        }

        String returnSendTime = systemConfigService.getValueByKey(Constants.RETURN_SEND_TIME);
        Date agreedReturnTime = storeOrder.getAgreedReturnTime();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(agreedReturnTime);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        Date calendarTime = calendar.getTime();
        Date addDays = DateUtils.addDays(calendarTime, Integer.parseInt(returnSendTime) + 1);
        // 未到售后截止时间继续循环
        if (DateUtil.dateNew(new Date()).getTime() < addDays.getTime()) {
            return Boolean.FALSE;
        }
        //变更订单状态为退款已取消
        storeOrder.setRefundStatus(6);
//        storeOrder.setIsSystemDel(true);
        ArrayList<StoreOrderInfo> storeOrderInfos = new ArrayList<>();
        for (StoreOrderInfo storeOrderInfo : storeOrderInfoList) {
            storeOrderInfo.setRefundStatus(6);
            storeOrderInfos.add(storeOrderInfo);
        }

        Boolean execute = transactionTemplate.execute(e -> {
            storeOrderService.updateById(storeOrder);
            storeOrderInfoService.updateBatchById(storeOrderInfos);
            // 写订单日志
            storeOrderStatusService.createLog(storeOrder.getId(), "RefundCancel", 1, "已过寄出时间，退款已取消");
            return Boolean.TRUE;
        });
        if (!execute) {
            throw new VcaException("过售后截止时间自动取消退款失败");
        }
        return Boolean.FALSE;
    }

    /**
     * @Description:推送消息提醒
     * @author:chenbing
     * @date 2022/12/30 15:31
     */
    @Override
    public boolean pushMessageTip(StoreOrder storeOrder, String reason) {
        List<StoreOrderInfo> orderInfoList = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()));
        SystemNotification paySuccessOfEvent = systemNotificationService.getByMark(OrderRedisConstans.CANCEL_ORDER_BY_SYSTEM);
        if (paySuccessOfEvent.getIsRoutine().equals(1)) {
            // TODO: 2022/12/30 生成小程序订阅消息
            orderCancelPushMessageRoutine(storeOrder, orderInfoList, paySuccessOfEvent.getRoutineId(), reason);
        }
        if (paySuccessOfEvent.getIsWechat().equals(1)) {
            // TODO: 2023/1/3 公众号模板消息
            orderCancelPushMessagePublic(storeOrder, orderInfoList, paySuccessOfEvent.getWechatId(), reason);
        }
        if (paySuccessOfEvent.getIsSms().equals(1)) {
            // TODO: 2023/1/3 发送短信
            SmsTemplate smsTemplate = smsTemplateService.getDetail(paySuccessOfEvent.getSmsId());
            if (storeOrder.getType() == 1) {
                StoreOrderInfo orderInfo = orderInfoList.get(0);
                generateSmsOrderAutoCancel(orderInfo, smsTemplate, orderInfo.getName(), reason, null);
            } else {
                for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                    if (storeOrderInfo.getType() == 4) {
                        String name = storeOrderInfo.getName();
                        if (name.length() > 13) {
                            name = storeOrderInfo.getName().substring(0, 13);
                        }
//                        if (orderInfoList.size() > 1) {
//                            name = name + "等商品";
//                        }
                        generateSmsOrderAutoCancel(storeOrderInfo, smsTemplate, name, reason, storeOrder.getUid());
                        break;
                    }
                    generateSmsOrderAutoCancel(storeOrderInfo, smsTemplate, storeOrderInfo.getName(), reason, storeOrder.getUid());
                }
            }
        }
        return Boolean.TRUE;
    }

    private void orderCancelPushMessagePublic(StoreOrder storeOrder, List<StoreOrderInfo> orderInfoList, Integer wechatId, String reason) {
        if (storeOrder.getType() == 1) {
            cancelPublic(orderInfoList.get(0), wechatId, reason, storeOrder.getUid(), orderInfoList.get(0).getName());
        } else {
            for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                if (storeOrderInfo.getType() == 4) {
                    String name = storeOrderInfo.getName();
                    if (name.length() > 13) {
                        name = storeOrderInfo.getName().substring(0, 13);
                    }
//                    name = name + "等商品";
                    cancelPublic(storeOrderInfo, wechatId, reason, storeOrder.getUid(), name);
                    break;
                } else {
                    cancelPublic(storeOrderInfo, wechatId, reason, storeOrder.getUid(), storeOrderInfo.getName());
                }
            }
        }
    }

    private void cancelPublic(StoreOrderInfo storeOrderInfo, Integer wechatId, String reason, Integer uid, String name) {
        HashMap<String, Object> messageMap = new HashMap<>();
        messageMap.put("first", "订单取消通知");
        messageMap.put("keyword1", storeOrderInfo.getOrderNo());
        messageMap.put("keyword2", name);
        messageMap.put("keyword3", reason);
        messageMap.put("keyword4", "0.00");
        messageMap.put("keyword5", DateUtil.format(new Date(), Constants.DATE_FORMAT));
        messageMap.put("remark", "如有需要请重新下单");
        String pageUrl = "pages/user-order-details/index?orderNo=" + storeOrderInfo.getOrderNo();
        UserToken buyerToken = null;
        if (storeOrderInfo.getType() == 4) {
            storeOrderInfo.setBuyer(uid);
            storeOrderInfo.setLecturer(null);
        }
        if (ObjectUtil.isNotNull(storeOrderInfo.getBuyer())) {
            buyerToken = userTokenService.getTokenByUserId(storeOrderInfo.getBuyer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        UserToken lecturerToken = null;
        if (ObjectUtil.isNotNull(storeOrderInfo.getLecturer())) {
            lecturerToken = userTokenService.getTokenByUserId(storeOrderInfo.getLecturer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        if (Objects.equals(storeOrderInfo.getBuyer(), storeOrderInfo.getLecturer())) {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, messageMap, buyerToken.getToken());
            }
        } else {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, messageMap, buyerToken.getToken());
            }
            if (ObjectUtil.isNotNull(lecturerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, messageMap, lecturerToken.getToken());
            }
        }
    }

    /**
     * 商品订单未发货取消订单
     *
     * @param storeOrder
     * @return
     */
    @Override
    public Boolean productCancelOrder(StoreOrder storeOrder) {
        try {
            /*
             * 1、修改订单状态 （用户操作的时候已处理）
             * 2、写订单日志（用户操作的时候已处理）
             * 3、回滚商品库存（加）/销量（减）；虚拟物品回滚限量（加）/预约人数（减）、礼品卡回滚,将订单号放到redis指定的key中【Task】
             * 4、消息通知（生成对应的模板消息存入对应的key中）【Task】
             * */
            //回滚礼品卡
            Boolean execute = transactionTemplate.execute(e -> {
                if (storeOrder.getCouponId() > 0) {
                    UserCard userCard = userCardService.getById(storeOrder.getCouponId());
                    userCard.setStutus(CouponConstants.STORE_COUPON_USER_STATUS_USABLE);
                    userCardService.updateById(userCard);
                }
                //回滚库存
                VcaProductStockVo vcaProductStockVo = vcaOrderService.rollBackStock(storeOrder);
                List<CourseScheduling> courseSchedulingList = vcaProductStockVo.getCourseSchedulingList();
                List<TalkScheduling> talkSchedulingList = vcaProductStockVo.getTalkSchedulingList();
                List<ExhibitionScheduling> exhibitionSchedulingList = vcaProductStockVo.getExhibitionSchedulingList();
                List<VcaProduct> vcaProducts = vcaProductStockVo.getVcaProducts();
                List<VcaProductAttrValue> vcaProductAttrValues = vcaProductStockVo.getVcaProductAttrValues();
                if (courseSchedulingList.size() > 0) {
                    courseSchedulingService.updateBatchById(courseSchedulingList);
                }
                if (talkSchedulingList.size() > 0) {
                    talkSchedulingService.updateBatchById(talkSchedulingList);
                }
                if (exhibitionSchedulingList.size() > 0) {
                    exhibitionSchedulingService.updateBatchById(exhibitionSchedulingList);
                }
                if (vcaProducts.size() > 0) {
                    vcaProductService.updateBatchById(vcaProducts);
                }
                if (vcaProductAttrValues.size() > 0) {
                    vcaProductAttrValueService.updateBatchById(vcaProductAttrValues);
                }
//                // TODO: 2022/12/30 推送消息提醒
//                frontOrderCancel(storeOrder);
                return Boolean.TRUE;
            });
            if (!execute) {
                throw new VcaException("取消订单失败");
            } else {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 活动消息通知
     *
     * @param storeOrder
     */
    public Boolean activityCancelPushMessage(StoreOrder storeOrder, Long schedulingId) {
        SystemNotification paySuccessOfEvent = systemNotificationService.getByMark(OrderRedisConstans.CANCEL_ACTIVITY_OF_EVENT);
        List<StoreOrderInfo> storeOrderInfos = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()).eq(StoreOrderInfo::getStatus, 1).eq(StoreOrderInfo::getRefundStatus, 2));

        StoreOrderInfo myStoreOrderInfo = new StoreOrderInfo();
        String name = "";
        for (StoreOrderInfo storeOrderInfo : storeOrderInfos) {
            if (storeOrderInfo.getSchedulingId().equals(schedulingId)) {
                BeanUtils.copyProperties(storeOrderInfo, myStoreOrderInfo);
            }
        }
        if (myStoreOrderInfo.getType().equals(1)) {
            Course course = courseService.getById(myStoreOrderInfo.getTaokeAboutCourseId());
            if (ObjectUtil.isNotNull(course)) {
                name = course.getName();
            }
        } else {
            name = myStoreOrderInfo.getName();
        }

        String cancellationReasons = "";
        if (paySuccessOfEvent.getIsRoutine().equals(1)) {
            // TODO: 2022/12/30 生成小程序订阅消息


            switch (storeOrder.getType()) {
                case 0:
                case 1:
                    CourseScheduling scheduling = courseSchedulingService.getById(schedulingId);
                    if (ObjectUtil.isNotNull(scheduling)) {
                        cancellationReasons = scheduling.getCancellationReasons();
                    }
                    break;
                case 2:
                    TalkScheduling talkScheduling = talkSchedulingService.getById(schedulingId);
                    if (ObjectUtil.isNotNull(talkScheduling)) {
                        cancellationReasons = talkScheduling.getCancellationReasons();
                    }
                case 3:
                    ExhibitionScheduling exhibitionScheduling = exhibitionSchedulingService.getById(schedulingId);
                    if (ObjectUtil.isNotNull(exhibitionScheduling)) {
                        cancellationReasons = exhibitionScheduling.getCancellationReasons();
                    }
                    break;
                default:
                    break;
            }

            // 活动名称{{thing1.DATA}}活动时间{{time2.DATA}}活动状态{{phrase4.DATA}}取消原因{{thing5.DATA}}
            HashMap<String, String> messageMap = new HashMap<>();
            messageMap.put("thing1", name);
            messageMap.put("time2", myStoreOrderInfo.getSchedulingDate() + " " + myStoreOrderInfo.getSchedulingStartTime());
            messageMap.put("phrase4", "活动取消");
            messageMap.put("thing5", cancellationReasons);
            activityCancelRoutine(messageMap, myStoreOrderInfo, paySuccessOfEvent.getRoutineId());
        }
        if (paySuccessOfEvent.getIsWechat().equals(1)) {
            // TODO: 2023/1/3 公众号模板消息
            //{{first.DATA}}服务单号：{{keyword1.DATA}}取消原因：{{keyword2.DATA}}{{remark.DATA}}
            HashMap<String, Object> map = new HashMap<>();
            map.put("first", "活动取消通知");
            map.put("keyword1", storeOrder.getOrderId());
            map.put("keyword2", cancellationReasons);
            map.put("remark", "欢迎再次购买！");
            activityCancelByPublicAccount(map, paySuccessOfEvent.getWechatId(), storeOrder);
        }
        if (paySuccessOfEvent.getIsSms().equals(1)) {
            // TODO: 2023/1/3 发送短信
            SmsTemplate smsTemplate = smsTemplateService.getDetail(paySuccessOfEvent.getSmsId());
            if (Objects.equals(myStoreOrderInfo.getBuyer(), myStoreOrderInfo.getLecturer())) {
                smsOrderActivityCancel(myStoreOrderInfo.getBuyer(), name, myStoreOrderInfo, smsTemplate.getTempId());
            } else {
                smsOrderActivityCancel(myStoreOrderInfo.getBuyer(), name, myStoreOrderInfo, smsTemplate.getTempId());
                smsOrderActivityCancel(myStoreOrderInfo.getLecturer(), name, myStoreOrderInfo, smsTemplate.getTempId());
            }
        }
        return Boolean.TRUE;
    }


    /**
     * 后台取消订单消息通知
     *
     * @param storeOrder
     */
    public Boolean adminOrderCancelPushMessage(StoreOrder storeOrder) {
        SystemNotification paySuccessOfEvent = systemNotificationService.getByMark(OrderRedisConstans.CANCEL_APPOIMENT);
        List<StoreOrderInfo> storeOrderInfoList = storeOrderInfoService.getListByOrderNo(storeOrder.getOrderId());


        if (paySuccessOfEvent.getIsRoutine().equals(1)) {
            // TODO: 2022/12/30 生成小程序订阅消息
            String name = storeOrderInfoList.get(0).getName();
            if (name.length() > 16) {
                name = name.substring(0, 16);
            }

            // 活动名称{{thing1.DATA}}取消时间{{time3.DATA}}操作人{{short_thing4.DATA}}
            HashMap<String, String> messageMap = new HashMap<>();
            messageMap.put("thing1", name);
            messageMap.put("time3", DateUtil.format(storeOrder.getRefundReasonTime(), Constants.DATE_FORMAT));
            messageMap.put("short_thing4", "LECO");//
            adminOrderCancelRoutine(messageMap, storeOrderInfoList.get(0), paySuccessOfEvent.getRoutineId());
        }
        if (paySuccessOfEvent.getIsWechat().equals(1)) {
            // TODO: 2023/1/3 公众号模板消息
            String name = storeOrderInfoList.get(0).getName();
            if (name.length() > 16) {
                name = name.substring(0, 16);
            }
            //{{first.DATA}}会员名称：{{keyword1.DATA}}订单编号：{{keyword2.DATA}}取消时间：{{keyword3.DATA}}{{remark.DATA}}
            HashMap<String, Object> message = new HashMap<>();
            message.put("first", "订单取消通知");
            message.put("keyword1", storeOrderInfoList.get(0).getLecturerName());
            message.put("keyword2", storeOrder.getOrderId());
            message.put("keyword3", cn.hutool.core.date.DateUtil.format(new Date(), Constants.DATE_FORMAT));
            message.put("remark", "欢迎再次购买！");
            adminOrderCancelByPublicAccount(message, paySuccessOfEvent.getWechatId(), storeOrder);
        }
        if (paySuccessOfEvent.getIsSms().equals(1)) {
            // TODO: 2023/1/3 发送短信
            String name = storeOrderInfoList.get(0).getName();
            if (name.length() > 16) {
                name = name.substring(0, 16);
            }
            SmsTemplate smsTemplate = smsTemplateService.getDetail(paySuccessOfEvent.getSmsId());
            if (Objects.equals(storeOrderInfoList.get(0).getBuyer(), storeOrderInfoList.get(0).getLecturer())) {
                smsAdminOrderCancel(storeOrderInfoList.get(0).getBuyer(), name, storeOrderInfoList.get(0), smsTemplate.getTempId());
            } else {
                smsAdminOrderCancel(storeOrderInfoList.get(0).getBuyer(), name, storeOrderInfoList.get(0), smsTemplate.getTempId());
                smsAdminOrderCancel(storeOrderInfoList.get(0).getLecturer(), name, storeOrderInfoList.get(0), smsTemplate.getTempId());
            }
        }
        return Boolean.TRUE;
    }

    private void generateSmsOrderAutoCancel(StoreOrderInfo orderInfo, SmsTemplate smsTemplate, String name, String reason, Integer userId) {
        if (orderInfo.getType() == 4) {
            smsOrderAutoCancel(userId, reason, name, orderInfo, smsTemplate.getTempId());
        } else {
            if (Objects.equals(orderInfo.getBuyer(), orderInfo.getLecturer())) {
                smsOrderAutoCancel(orderInfo.getBuyer(), reason, name, orderInfo, smsTemplate.getTempId());
            } else {
                smsOrderAutoCancel(orderInfo.getBuyer(), reason, name, orderInfo, smsTemplate.getTempId());
                smsOrderAutoCancel(orderInfo.getLecturer(), reason, name, orderInfo, smsTemplate.getTempId());
            }
        }
    }


    /**
     * @Description:生成订单超时自动取消短信模板
     * @author:chenbing
     * @date 2023/1/4 11:25
     */
    private void smsOrderAutoCancel(Integer userId, String reason, String name, StoreOrderInfo orderInfo, String tempId) {
        String pageUrl = "pages/user-order-details/index?orderNo=" + orderInfo.getOrderNo();
        if (ObjectUtil.isNotNull(userId)) {
            User user = userService.getById(userId);
            if (ObjectUtil.isNotNull(user.getPhone())) {
                smsService.sendOrderAutoCancel(name, reason, user.getPhone(), tempId, pageUrl);
            }
        } else {
            smsService.sendOrderAutoCancel(name, reason, orderInfo.getLecturerPhone(), tempId, pageUrl);
        }
    }


    /**
     * @Description:生成小程序订阅消息
     * @author:chenbing
     * @date 2022/12/30 15:55
     */
    private void orderCancelPushMessageRoutine(StoreOrder storeOrder, List<StoreOrderInfo> orderInfoList, Integer routineId, String reason) {
        if (storeOrder.getType() == 1) {
            cancelRoutine(orderInfoList.get(0), routineId, reason, storeOrder.getUid(), orderInfoList.get(0).getName());
        } else {
            for (StoreOrderInfo storeOrderInfo : orderInfoList) {
                if (storeOrderInfo.getType() == 4) {
                    String name = storeOrderInfo.getName();
                    if (name.length() > 13) {
                        name = storeOrderInfo.getName().substring(0, 13);
                    }
//                    name = name + "等商品";
                    cancelRoutine(storeOrderInfo, routineId, reason, storeOrder.getUid(), name);
                    break;
                } else {
                    cancelRoutine(storeOrderInfo, routineId, reason, storeOrder.getUid(), storeOrderInfo.getName());
                }
            }
        }
    }

    public void cancelRoutine(StoreOrderInfo storeOrderInfo, Integer routineId, String reason, Integer uid, String name) {
        HashMap<String, String> messageMap = new HashMap<>();
        //商品名称{{thing6.DATA}}订单号{{character_string20.DATA}}取消原因{{thing1.DATA}}取消时间{{date2.DATA}}备注{{thing4.DATA}}
        messageMap.put("thing6", name);
        messageMap.put("character_string20", storeOrderInfo.getOrderNo());
        messageMap.put("thing1", reason);
        messageMap.put("date2", DateUtil.format(new Date(), Constants.DATE_FORMAT));
        messageMap.put("thing4", "您购买的商品已取消成功。");
        UserToken buyerToken = null;
        if (storeOrderInfo.getType() == 4) {
            storeOrderInfo.setBuyer(uid);
            storeOrderInfo.setLecturer(null);
        }
        String pageUrl = "pages/user-order-details/index?orderNo=" + storeOrderInfo.getOrderNo();
        if (ObjectUtil.isNotNull(storeOrderInfo.getBuyer())) {
            buyerToken = userTokenService.getTokenByUserId(storeOrderInfo.getBuyer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        UserToken lecturerToken = null;
        if (ObjectUtil.isNotNull(storeOrderInfo.getLecturer())) {
            lecturerToken = userTokenService.getTokenByUserId(storeOrderInfo.getLecturer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        if (Objects.equals(storeOrderInfo.getBuyer(), storeOrderInfo.getLecturer())) {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, buyerToken.getToken(), pageUrl);
            }
        } else {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, buyerToken.getToken(), pageUrl);
            }
            if (ObjectUtil.isNotNull(lecturerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, lecturerToken.getToken(), pageUrl);
            }
        }
    }

    /**
     * 活动取消订阅消息
     *
     * @param storeOrderInfo
     * @param routineId
     * @param messageMap
     */
    public void activityCancelRoutine(HashMap<String, String> messageMap, StoreOrderInfo storeOrderInfo, Integer routineId) {
        UserToken buyerToken = new UserToken();
        if (ObjectUtil.isNotNull(storeOrderInfo.getBuyer())) {
            buyerToken = userTokenService.getTokenByUserId(storeOrderInfo.getBuyer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        UserToken lecturerToken = new UserToken();
        if (ObjectUtil.isNotNull(storeOrderInfo.getLecturer())) {
            lecturerToken = userTokenService.getTokenByUserId(storeOrderInfo.getLecturer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        if (Objects.equals(storeOrderInfo.getBuyer(), storeOrderInfo.getLecturer())) {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, buyerToken.getToken(), "pages/user-order-details/index?orderNo=" + storeOrderInfo.getOrderNo());
            }
        } else {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, buyerToken.getToken(), "pages/user-order-details/index?orderNo=" + storeOrderInfo.getOrderNo());
            }
            if (ObjectUtil.isNotNull(lecturerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, lecturerToken.getToken(), "pages/user-order-details/index?orderNo=" + storeOrderInfo.getOrderNo());
            }
        }
    }

    /**
     * 活动取消公众号消息通知
     *
     * @param message
     * @param wechatId
     * @param storeOrder
     */
    private void activityCancelByPublicAccount(HashMap<String, Object> message, Integer wechatId, StoreOrder storeOrder) {
        List<StoreOrderInfo> orderInfoList = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()));
        String pageUrl = "pages/user-order-details/index?orderNo=" + storeOrder.getOrderId();
        UserToken buyerToken = new UserToken();
        if (ObjectUtil.isNotNull(orderInfoList.get(0).getBuyer())) {
            buyerToken = userTokenService.getTokenByUserId(orderInfoList.get(0).getBuyer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        UserToken lecturerToken = new UserToken();
        if (ObjectUtil.isNotNull(orderInfoList.get(0).getLecturer())) {
            lecturerToken = userTokenService.getTokenByUserId(orderInfoList.get(0).getLecturer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        if (Objects.equals(orderInfoList.get(0).getBuyer(), orderInfoList.get(0).getLecturer())) {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, buyerToken.getToken());
            }
        } else {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, buyerToken.getToken());
            }
            if (ObjectUtil.isNotNull(lecturerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, lecturerToken.getToken());
            }
        }
    }

    /**
     * 活动取消短信模板
     *
     * @param userId
     * @param name
     * @param orderInfo
     * @param tempId
     */
    private void smsOrderActivityCancel(Integer userId, String name, StoreOrderInfo orderInfo, String tempId) {
        if (ObjectUtil.isNotNull(userId)) {
            User user = userService.getById(userId);
            if (ObjectUtil.isNotNull(user.getPhone())) {
                smsService.sendActivityCancel(name, user.getPhone(), tempId, "pages/user-order-details/index?orderNo=" + orderInfo.getOrderNo());
            }
        } else {
            smsService.sendActivityCancel(name, orderInfo.getLecturerPhone(), tempId, "pages/user-order-details/index?orderNo=" + orderInfo.getOrderNo());
        }
    }

    /**
     * 后台清单取消订阅消息
     *
     * @param storeOrderInfo
     * @param routineId
     * @param messageMap
     */
    public void adminOrderCancelRoutine(HashMap<String, String> messageMap, StoreOrderInfo storeOrderInfo, Integer routineId) {
        UserToken buyerToken = new UserToken();
        if (ObjectUtil.isNotNull(storeOrderInfo.getBuyer())) {
            buyerToken = userTokenService.getTokenByUserId(storeOrderInfo.getBuyer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        UserToken lecturerToken = new UserToken();
        if (ObjectUtil.isNotNull(storeOrderInfo.getLecturer())) {
            lecturerToken = userTokenService.getTokenByUserId(storeOrderInfo.getLecturer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        if (Objects.equals(storeOrderInfo.getBuyer(), storeOrderInfo.getLecturer())) {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, buyerToken.getToken(), "pages/user-order-details/index?orderNo=" + storeOrderInfo.getOrderNo());
            }
        } else {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, buyerToken.getToken(), "pages/user-order-details/index?orderNo=" + storeOrderInfo.getOrderNo());
            }
            if (ObjectUtil.isNotNull(lecturerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, lecturerToken.getToken(), "pages/user-order-details/index?orderNo=" + storeOrderInfo.getOrderNo());
            }
        }
    }

    /**
     * 后台清单取消公众号消息通知
     *
     * @param message
     * @param wechatId
     * @param storeOrder
     */
    private void adminOrderCancelByPublicAccount(HashMap<String, Object> message, Integer wechatId, StoreOrder storeOrder) {
        List<StoreOrderInfo> orderInfoList = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()));
        String pageUrl = "pages/user-order-details/index?orderNo=" + storeOrder.getOrderId();
        UserToken buyerToken = new UserToken();
        if (ObjectUtil.isNotNull(orderInfoList.get(0).getBuyer())) {
            buyerToken = userTokenService.getTokenByUserId(orderInfoList.get(0).getBuyer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        UserToken lecturerToken = new UserToken();
        if (ObjectUtil.isNotNull(orderInfoList.get(0).getLecturer())) {
            lecturerToken = userTokenService.getTokenByUserId(orderInfoList.get(0).getLecturer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        if (Objects.equals(orderInfoList.get(0).getBuyer(), orderInfoList.get(0).getLecturer())) {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, buyerToken.getToken());
            }
        } else {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, buyerToken.getToken());
            }
            if (ObjectUtil.isNotNull(lecturerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, lecturerToken.getToken());
            }
        }
    }

    /**
     * 后台清单取消短信模板
     *
     * @param userId
     * @param name
     * @param orderInfo
     * @param tempId
     */
    private void smsAdminOrderCancel(Integer userId, String name, StoreOrderInfo orderInfo, String tempId) {
        String pageUrl = "pages/user-order-details/index?orderNo=" + orderInfo.getOrderNo();
        if (ObjectUtil.isNotNull(userId)) {
            User user = userService.getById(userId);
            if (ObjectUtil.isNotNull(user.getPhone())) {
                smsService.sendOrderAppointment(name, user.getPhone(), tempId, pageUrl);
            }
        } else {
            smsService.sendOrderAppointment(name, orderInfo.getLecturerPhone(), tempId, pageUrl);
        }
    }


    /**
     * 前台订单取消消息通知
     *
     * @param storeOrder
     * @return
     */
    public boolean frontOrderCancel(StoreOrder storeOrder) {
        List<StoreOrderInfo> orderInfoList = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()));
        SystemNotification paySuccessOfEvent = systemNotificationService.getByMark(OrderRedisConstans.CANCEL_ORDER_OF_PRODUCT);
        if (paySuccessOfEvent.getIsRoutine().equals(1)) {
            // TODO: 2022/12/30 生成小程序订阅消息
            frontOrderCancelPushMessageRoutine(storeOrder, orderInfoList, paySuccessOfEvent.getRoutineId());
        }
        if (paySuccessOfEvent.getIsWechat().equals(1)) {
            // TODO: 2023/1/3 公众号模板消息
            String name = orderInfoList.get(0).getName();
            if (orderInfoList.size() > 1 && orderInfoList.get(0).getType().equals(4)) {
                if (name.length() > 13) {
                    name = name.substring(0, 13) + "等商品";
                }
            } else {
                if (name.length() > 16) {
                    name = name.substring(0, 16);
                }
            }
            //{{first.DATA}}订单编号：{{keyword1.DATA}}商品名称：{{keyword2.DATA}}取消原因：{{keyword3.DATA}}退款金额：{{keyword4.DATA}}取消时间：{{keyword5.DATA}}{{remark.DATA}}
            HashMap<String, Object> message = new HashMap<>();
            message.put("first", "订单取消通知");
            message.put("keyword1", storeOrder.getOrderId());
            message.put("keyword2", name);
            message.put("keyword3", "订单取消");
            message.put("keyword4", "0.00");
            message.put("keyword5", DateUtil.format(new Date(), Constants.DATE_FORMAT));
            message.put("remark", "欢迎再次购买！");
            frontOrderCancelByPublicAccount(message, paySuccessOfEvent.getWechatId(), storeOrder);
        }
        if (paySuccessOfEvent.getIsSms().equals(1)) {
            // TODO: 2023/1/3 发送短信
            SmsTemplate smsTemplate = smsTemplateService.getDetail(paySuccessOfEvent.getSmsId());
            StoreOrderInfo orderInfo = orderInfoList.get(0);
            frontSmsOrderCancel(orderInfo, smsTemplate, storeOrder.getUid());
        }
        return Boolean.TRUE;
    }

    /**
     * 前台订单取消小程序订阅消息通知
     *
     * @param storeOrder
     * @param orderInfoList
     * @param routineId
     */
    private void frontOrderCancelPushMessageRoutine(StoreOrder storeOrder, List<StoreOrderInfo> orderInfoList, Integer routineId) {
        String name = orderInfoList.get(0).getName();
        if (name.length() > 13) {
            name = orderInfoList.get(0).getName().substring(0, 13);
        }
        if (orderInfoList.size() > 1) {
            name = name + "等商品";
        }

        HashMap<String, String> messageMap = new HashMap<>();
        //商品名称{{thing6.DATA}}订单号{{character_string20.DATA}}取消原因{{thing1.DATA}}取消时间{{date2.DATA}}备注{{thing4.DATA}}
        messageMap.put("thing6", name);
        messageMap.put("character_string20", orderInfoList.get(0).getOrderNo());
        messageMap.put("thing1", "订单取消");
        messageMap.put("date2", DateUtil.format(new Date(), Constants.DATE_FORMAT));
        messageMap.put("thing4", "感谢您的光临！");
        UserToken buyerToken = new UserToken();
        if (orderInfoList.get(0).getType() == 4) {
            orderInfoList.get(0).setBuyer(storeOrder.getUid());
            orderInfoList.get(0).setLecturer(null);
        }
        if (ObjectUtil.isNotNull(orderInfoList.get(0).getBuyer())) {
            buyerToken = userTokenService.getTokenByUserId(orderInfoList.get(0).getBuyer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        UserToken lecturerToken = new UserToken();
        if (ObjectUtil.isNotNull(orderInfoList.get(0).getLecturer())) {
            lecturerToken = userTokenService.getTokenByUserId(orderInfoList.get(0).getLecturer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        if (Objects.equals(orderInfoList.get(0).getBuyer(), orderInfoList.get(0).getLecturer())) {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, buyerToken.getToken(), "pages/user-order-details/index?orderNo=" + orderInfoList.get(0).getOrderNo());
            }
        } else {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, buyerToken.getToken(), "pages/user-order-details/index?orderNo=" + orderInfoList.get(0).getOrderNo());
            }
            if (ObjectUtil.isNotNull(lecturerToken)) {
                templateMessageService.pushMiniTemplateMessage(routineId, messageMap, lecturerToken.getToken(), "pages/user-order-details/index?orderNo=" + orderInfoList.get(0).getOrderNo());
            }
        }
    }

    private void frontOrderCancelByPublicAccount(HashMap<String, Object> message, Integer wechatId, StoreOrder storeOrder) {

        List<StoreOrderInfo> orderInfoList = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()));
        String pageUrl = "pages/user-order-details/index?orderNo=" + storeOrder.getOrderId();
        UserToken buyerToken = new UserToken();
        if (ObjectUtil.isNotNull(orderInfoList.get(0).getBuyer())) {
            buyerToken = userTokenService.getTokenByUserId(orderInfoList.get(0).getBuyer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        UserToken lecturerToken = new UserToken();
        if (ObjectUtil.isNotNull(orderInfoList.get(0).getLecturer())) {
            lecturerToken = userTokenService.getTokenByUserId(orderInfoList.get(0).getLecturer(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        }
        if (Objects.equals(orderInfoList.get(0).getBuyer(), orderInfoList.get(0).getLecturer())) {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, buyerToken.getToken());
            }
        } else {
            if (ObjectUtil.isNotNull(buyerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, buyerToken.getToken());
            }
            if (ObjectUtil.isNotNull(lecturerToken)) {
                templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, lecturerToken.getToken());
            }
        }

    }

    /**
     * 前台订单取消短信消息通知
     *
     * @param orderInfo
     * @param smsTemplate
     * @param userId
     */
    private void frontSmsOrderCancel(StoreOrderInfo orderInfo, SmsTemplate smsTemplate, Integer userId) {
        String pageUrl = "pages/user-order-details/index?orderNo=" + orderInfo.getOrderNo();
        if (orderInfo.getType() == 4) {
            if (ObjectUtil.isNotNull(userId)) {
                User user = userService.getById(userId);
                if (ObjectUtil.isNotNull(user.getPhone())) {
                    smsService.sendOrderCancelProduct(orderInfo.getOrderNo(), user.getPhone(), smsTemplate.getTempId(), pageUrl);
                }
            } else {
                smsService.sendOrderCancelProduct(orderInfo.getOrderNo(), orderInfo.getLecturerPhone(), smsTemplate.getTempId(), pageUrl);
            }
        } else {
            if (Objects.equals(orderInfo.getBuyer(), orderInfo.getLecturer())) {
                if (ObjectUtil.isNotNull(orderInfo.getBuyer())) {
                    User user = userService.getById(orderInfo.getBuyer());
                    if (ObjectUtil.isNotNull(user.getPhone())) {
                        smsService.sendOrderCancelProduct(orderInfo.getOrderNo(), user.getPhone(), smsTemplate.getTempId(), pageUrl);
                    }
                } else {
                    smsService.sendOrderCancelProduct(orderInfo.getOrderNo(), orderInfo.getLecturerPhone(), smsTemplate.getTempId(), pageUrl);
                }
            } else {
                if (ObjectUtil.isNotNull(orderInfo.getBuyer())) {
                    User user = userService.getById(orderInfo.getBuyer());
                    if (ObjectUtil.isNotNull(user.getPhone())) {
                        smsService.sendOrderCancelProduct(orderInfo.getOrderNo(), user.getPhone(), smsTemplate.getTempId(), pageUrl);
                    }
                } else {
                    smsService.sendOrderCancelProduct(orderInfo.getOrderNo(), orderInfo.getLecturerPhone(), smsTemplate.getTempId(), pageUrl);
                }
                if (ObjectUtil.isNotNull(orderInfo.getLecturer())) {
                    User user = userService.getById(orderInfo.getLecturer());
                    if (ObjectUtil.isNotNull(user.getPhone())) {
                        smsService.sendOrderCancelProduct(orderInfo.getOrderNo(), user.getPhone(), smsTemplate.getTempId(), pageUrl);
                    }
                } else {
                    smsService.sendOrderCancelProduct(orderInfo.getOrderNo(), orderInfo.getLecturerPhone(), smsTemplate.getTempId(), pageUrl);
                }
            }
        }
    }


    /**
     * 同意退款消息通知
     *
     * @param storeOrder
     * @return
     */
    public Boolean orderConsentRefund(StoreOrder storeOrder, List<StoreOrderInfo> orderInfoList) {
        SystemNotification paySuccessOfEvent = systemNotificationService.getByMark(OrderRedisConstans.REFUND_ORDER_TO_SUCCESS);
        if (paySuccessOfEvent.getIsRoutine().equals(1)) {
            // TODO: 2022/12/30 生成小程序订阅消息
            //订单号{{character_string13.DATA}}退款原因{{thing9.DATA}}退款时间{{time8.DATA}}退款金额{{amount10.DATA}}退款类型{{phrase14.DATA}}
            HashMap<String, String> messageMap = new HashMap<>();
            messageMap.put("character_string13", storeOrder.getOrderId());
            messageMap.put("thing9", storeOrder.getRefundReasonWap());
            messageMap.put("time8", cn.hutool.core.date.DateUtil.format(new Date(), Constants.DATE_FORMAT));
            messageMap.put("amount10", storeOrder.getRefundPrice().toPlainString());
            messageMap.put("phrase14", "退货退款");
            if (ObjectUtil.isNotNull(storeOrder.getUid())) {
                UserToken userToken = userTokenService.getTokenByUserId(storeOrder.getUid(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
                templateMessageService.pushMiniTemplateMessage(paySuccessOfEvent.getRoutineId(), messageMap, userToken.getToken(), "pages/user-order-details/index?orderNo=" + storeOrder.getOrderId());
            }
        }
        if (paySuccessOfEvent.getIsWechat().equals(1)) {
            // TODO: 2023/1/3 公众号模板消息
            //{{first.DATA}}订单编号：{{keyword1.DATA}}充值账号：{{keyword2.DATA}}退款类型：{{keyword3.DATA}}退款金额：{{keyword4.DATA}}退款时间：{{keyword5.DATA}}{{remark.DATA}}
            HashMap<String, Object> message = new HashMap<>();
            message.put("first", "同意退款通知");
            message.put("keyword1", storeOrder.getOrderId());
            message.put("keyword2", "  ");
            message.put("keyword3", "退货退款");
            message.put("keyword4", storeOrder.getRefundPrice().toPlainString());
            message.put("keyword5", cn.hutool.core.date.DateUtil.format(new Date(), Constants.DATE_FORMAT));
            message.put("remark", "感谢您的使用！");
            orderAgreeRefundByPublicAccount(message, paySuccessOfEvent.getWechatId(), storeOrder);
        }
        if (paySuccessOfEvent.getIsSms().equals(1)) {
            // TODO: 2023/1/3 发送短信
            SmsTemplate smsTemplate = smsTemplateService.getDetail(paySuccessOfEvent.getSmsId());
            if (orderInfoList.size() > 1) {
                String name = orderInfoList.get(0).getName();
                if (name.length() > 13) {
                    name = orderInfoList.get(0).getName().substring(0, 13);
                }
                name = name + "等商品";
                smsOrderConsentRefund(storeOrder.getUid(), name, storeOrder, smsTemplate.getTempId());
            } else {
                String name = "";
                if (orderInfoList.get(0).getName().length() > 16) {
                    name = orderInfoList.get(0).getName().substring(0, 16);
                } else {
                    name = orderInfoList.get(0).getName();
                }
                smsOrderConsentRefund(storeOrder.getUid(), name, storeOrder, smsTemplate.getTempId());
            }

        }

        return Boolean.TRUE;
    }

    /**
     * 同意退款公众号消息通知
     *
     * @param message
     * @param wechatId
     * @param storeOrder
     */
    private void orderAgreeRefundByPublicAccount(HashMap<String, Object> message, Integer wechatId, StoreOrder storeOrder) {
        String pageUrl = "pages/user-order-details/index?orderNo=" + storeOrder.getOrderId();
        UserToken token = userTokenService.getTokenByUserId(storeOrder.getUid(), OrderRedisConstans.SYSTEM_TYPE_ROUTINE);
        if (ObjectUtil.isNotNull(token)) {
            templateMessageService.pushTemplatePublicMessage(pageUrl, wechatId, message, token.getToken());
        }
    }

    /**
     * 订单同意退款短信模板
     *
     * @param userId
     * @param name
     * @param order
     * @param tempId
     */
    private void smsOrderConsentRefund(Integer userId, String name, StoreOrder order, String tempId) {
        String pageUrl = "pages/user-order-details/index?orderNo=" + order.getOrderId();
        if (ObjectUtil.isNotNull(userId)) {
            User user = userService.getById(userId);
            if (ObjectUtil.isNotNull(user.getPhone())) {
                smsService.sendOrderRefund(name, order.getOrderId(), user.getPhone(), tempId, pageUrl);
            }
        }
    }


    /**
     * @return
     * @Description:回滚库存
     * @author:xyg
     * @date 2022/12/30 15:11
     */
    public VcaProductStockVo rollBackStock(StoreOrder storeOrder) {

        VcaStockResponse vcaStockResponse = new VcaStockResponse();
        List<VcaProduct> vcaProducts = new ArrayList<>();
        List<VcaProductAttrValue> vcaProductAttrValues = new ArrayList<>();
        switch (storeOrder.getType()) {
//            case 0:
//            case 1:
//                CourseScheduling courseSchedulings = rollBackStockOfCourse(storeOrder);
//                vcaStockResponse.setCourseSchedulingList(courseSchedulings);
//                break;
//            case 2:
//                TalkScheduling talkSchedulings = rollBackStockOfTalk(storeOrder);
//                vcaStockResponse.setTalkSchedulingList(talkSchedulings);
//                break;
//            case 3:
//                ExhibitionScheduling exhibitionSchedulings = rollBackStockOfExhibition(storeOrder);
//                vcaStockResponse.setExhibitionSchedulingList(exhibitionSchedulings);
//                break;
            case 4:
                VcaProductStockVo vcaProductStockVo1 = rollBackStockOfProduct(storeOrder);
                vcaProductStockVo1.getVcaProducts().forEach(vcaProduct -> {
                    vcaProducts.add(vcaProduct);
                });
                vcaProductStockVo1.getVcaProductAttrValues().forEach(vcaProductAttrValue -> {
                    vcaProductAttrValues.add(vcaProductAttrValue);
                });
                break;
            default:
                break;
        }
        VcaProductStockVo vcaProductStockVo = new VcaProductStockVo();
        vcaProductStockVo.setVcaProductAttrValues(vcaProductAttrValues);
        vcaProductStockVo.setVcaProducts(vcaProducts);
        return vcaProductStockVo;
    }

    /**
     * @Description:回滚商品库存
     * @author:chenbing
     * @date 2022/12/30 15:22
     */
    private VcaProductStockVo rollBackStockOfProduct(StoreOrder storeOrder) {

//        VcaProduct product = vcaProductService.getById(storeOrderInfo.getProductId());
//        product.setStock(product.getStock() + storeOrderInfo.getPayNum());
//        product.setSales(product.getSales() == 0 ? 0 : product.getSales() - storeOrderInfo.getPayNum());
//        VcaProductAttrValue productAttrValue = vcaProductAttrValueService.getById(storeOrderInfo.getAttrValueId());
//        productAttrValue.setStock(productAttrValue.getStock() + storeOrderInfo.getPayNum());
//        productAttrValue.setSales(productAttrValue.getSales() == 0 ? 0 : productAttrValue.getSales() - storeOrderInfo.getPayNum());
//
//        VcaStockResponse vcaStockResponse = new VcaStockResponse();
//        vcaStockResponse.setVcaProducts(product);
//        vcaStockResponse.setVcaProductAttrValues(productAttrValue);
//        return vcaStockResponse;
        List<StoreOrderInfo> orderInfoList = storeOrderInfoService.list(new LambdaQueryWrapper<StoreOrderInfo>().eq(StoreOrderInfo::getOrderNo, storeOrder.getOrderId()).eq(StoreOrderInfo::getRefundStatus, 2));
        List<VcaProduct> vcaProducts = new ArrayList<>();
        List<VcaProductAttrValue> vcaProductAttrValues = new ArrayList<>();
        orderInfoList.forEach(orderInfo -> {
            VcaProduct product = vcaProductService.getById(orderInfo.getProductId());
            product.setStock(product.getStock() + orderInfo.getPayNum());
            product.setSales(product.getSales() == 0 ? 0 : product.getSales() - orderInfo.getPayNum());
            VcaProductAttrValue productAttrValue = vcaProductAttrValueService.getById(orderInfo.getAttrValueId());
            productAttrValue.setStock(productAttrValue.getStock() + orderInfo.getPayNum());
            productAttrValue.setSales(productAttrValue.getSales() == 0 ? 0 : productAttrValue.getSales() - orderInfo.getPayNum());
            vcaProducts.add(product);
            vcaProductAttrValues.add(productAttrValue);
        });
        VcaProductStockVo vcaProductStockVo = new VcaProductStockVo();
        vcaProductStockVo.setVcaProducts(vcaProducts);
        vcaProductStockVo.setVcaProductAttrValues(vcaProductAttrValues);
        return vcaProductStockVo;
    }

    /**
     * @Description:回滚展览排期库存
     * @author:chenbing
     * @date 2022/12/30 15:21
     */
    private ExhibitionScheduling rollBackStockOfExhibition(StoreOrderInfo storeOrderInfo) {
        ExhibitionScheduling exhibitionScheduling = exhibitionSchedulingService.getOne(new LambdaQueryWrapper<ExhibitionScheduling>()
                .eq(ExhibitionScheduling::getExhibitionId, storeOrderInfo.getMainId())
                .eq(ExhibitionScheduling::getId, storeOrderInfo.getSchedulingId()));
        exhibitionScheduling.setQuota(exhibitionScheduling.getQuota() + storeOrderInfo.getPayNum());
        exhibitionScheduling.setNumberOfAppointments(exhibitionScheduling.getNumberOfAppointments() == 0 ? 0 : exhibitionScheduling.getNumberOfAppointments() - storeOrderInfo.getPayNum());
        return exhibitionScheduling;
    }

    /**
     * @Description:回滚讲座排期库存
     * @author:chenbing
     * @date 2022/12/30 15:18
     */
    private TalkScheduling rollBackStockOfTalk(StoreOrderInfo storeOrderInfo) {
        TalkScheduling talkScheduling = talkSchedulingService.getOne(new LambdaQueryWrapper<TalkScheduling>()
                .eq(TalkScheduling::getTalkId, storeOrderInfo.getMainId())
                .eq(TalkScheduling::getId, storeOrderInfo.getSchedulingId()));
        talkScheduling.setQuota(talkScheduling.getQuota() + storeOrderInfo.getPayNum());
        talkScheduling.setNumberOfAppointments(talkScheduling.getNumberOfAppointments() == 0 ? 0 : talkScheduling.getNumberOfAppointments() - storeOrderInfo.getPayNum());
        return talkScheduling;
    }

    /**
     * @Description:回滚课程排期库存
     * @author:chenbing
     * @date 2022/12/30 15:15
     */
    private CourseScheduling rollBackStockOfCourse(StoreOrderInfo storeOrderInfo) {
        LambdaQueryWrapper<CourseScheduling> lqw = new LambdaQueryWrapper<CourseScheduling>()
                .eq(CourseScheduling::getId, storeOrderInfo.getSchedulingId());
        if (Objects.equals(storeOrderInfo.getType(), Constants.ORDER_TYPE_PACKAGE)) {
            lqw.eq(CourseScheduling::getCourseId, storeOrderInfo.getTaokeAboutCourseId());
        } else {
            lqw.eq(CourseScheduling::getCourseId, storeOrderInfo.getMainId());
        }
        CourseScheduling scheduling = courseSchedulingService.getOne(lqw);
        scheduling.setExternalLimit(scheduling.getExternalLimit() + storeOrderInfo.getPayNum());
        scheduling.setExternalAppointment(scheduling.getExternalAppointment() == 0 ? 0 : scheduling.getExternalAppointment() - storeOrderInfo.getPayNum());

        return scheduling;
    }

}
